﻿/*
 * Copyright (C) 2021. Huawei Device Co., Ltd. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the MIT License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * MIT License for more details.
 */

#include "UICulture.h"
#include "unicode/fmtable.h"
#include "unicode/msgfmt.h"

namespace DuiLib {
using namespace icu;

UICulture::~UICulture()
{
    for ( auto &cultureImplment : cultureImplements) {
        if (cultureImplment != nullptr) {
            continue;
        }
        delete cultureImplment;
        cultureImplment = nullptr;
    }
    cultureImplements.clear();
}

UICulture* UICulture::GetInstance()
{
    static UICulture instance;
    return &instance;
}

void UICulture::setResPath(LPCTSTR path)
{
    if (path == nullptr) {
        return;
    }
    wstring pathTemp = path;
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment != nullptr && cultureImplment->GetResPath() == pathTemp) {
            return; // 当前路径已配置，不重复配置
        }
    }
    auto cultureImplTemp = new (std::nothrow) UICultureImplement;
    if (cultureImplTemp == nullptr) {
        return;
    }
    cultureImplTemp->setResPath(path);
    if (!defaultLocal.empty()) {
        cultureImplTemp->setLocale(defaultLocal.c_str(), defaultLoadAll);
    }
    cultureImplements.push_back(cultureImplTemp);
}

void UICulture::setLocale(LPCTSTR locale, bool loadAll)
{
    if (locale == nullptr) {
        return;
    }
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        cultureImplment->setLocale(locale, loadAll);
    }
    if (defaultLocal.empty()) {
        defaultLocal = locale;
        defaultLoadAll = loadAll;
    }
}

LayoutDirection UICulture::getDirection()
{
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        return cultureImplment->getDirection();
    }
    return DIRECTION_LTR;
}

CDuiString UICulture::ParseBind(LPCTSTR pstrValue)
{
    if (pstrValue == nullptr) {
        return CDuiString();
    }
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        auto text = cultureImplment->ParseBind(pstrValue);
        if (text.IsEmpty()) {
            continue;
        }
        return text;
    }
    return CDuiString();
}

CDuiString UICulture::GetString(LPCTSTR key)
{
    if (key == nullptr) {
        return CDuiString();
    }
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        auto text = cultureImplment->GetString(key);
        if (text.IsEmpty()) {
            continue;
        }
        return text;
    }
    return CDuiString();
}

CDuiString UICulture::GetLocalString(LPCTSTR key)
{
    if (key == nullptr) {
        return CDuiString();
    }
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        auto text = cultureImplment->GetLocalString(key);
        if (text.IsEmpty()) {
            continue;
        }
        return text;
    }
    return CDuiString();
}

std::wstring UICulture::GetLocaleLanguage()
{
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        return cultureImplment->GetLocaleLanguage();
    }
    return L"en_us";
}

void UICulture::SetCustomFont(wstring fontstr)
{
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        cultureImplment->SetCustomFont(fontstr);
    }
}

wstring UICulture::GetCustomFont()
{
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        return cultureImplment->GetCustomFont();
    }
    return L"";
}

std::wstring UICulture::GetMultiVarStringForDotnet(const wstring& localString,
    const vector<int>& nums, const string& language)
{
    UnicodeString msgSl;
    FieldPosition fPos = 0;

    UErrorCode status = U_ZERO_ERROR;
    Locale locale = language.c_str();

    wstring wstrRet = localString;
    if (nums.size() == 0) {
        return wstrRet;
    }

    UnicodeString msgPatSl = wstrRet.c_str();
    MessageFormat* altMsgfmtSl = new MessageFormat(msgPatSl, locale, status);
    if (altMsgfmtSl == nullptr) {
        return wstrRet;
    }
    Formattable* arg = new Formattable[sizeof(Formattable) * nums.size()];
    if (arg == nullptr) {
        delete altMsgfmtSl;
        return wstrRet;
    }
    std::copy(nums.begin(), nums.end(), arg);
    altMsgfmtSl->format(arg, (int32_t)nums.size(), msgSl, fPos, status);

    delete altMsgfmtSl;
    altMsgfmtSl = nullptr;

    delete[] arg;
    arg = nullptr;

    //ICU内部全部是unicode所以这里强转到wchar_t,在多字符集下可能会编译出错
    wstring wstrMsgSlBuf;
    if (msgSl.getTerminatedBuffer() != NULL) {
        wstrMsgSlBuf = (wchar_t*)msgSl.getTerminatedBuffer();
    }
    return wstrMsgSlBuf;
}

std::wstring UICulture::GetMultiVarStr(const wstring &strIDS, const vector<int> &vecNum, int count)
{
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        auto text = cultureImplment->GetMultiVarStr(strIDS, vecNum, count);
        if (text.empty()) {
            continue;
        }
        return text;
    }
    return L"";
}

wstring UICulture::GetTextFromHtmlText(CPaintManagerUI* pManager, LPCTSTR pstrText, int iFont)
{
    if (pManager == nullptr || pstrText == nullptr) {
        return L"";
    }
    return UICultureImplement::GetTextFromHtmlText(pManager, pstrText, iFont);
}

CDuiString UICulture::GetMultiVarString(LPCTSTR originalString, ...)
{
    DuiLib::CDuiString formattedString = UICulture::GetString(originalString);
    int32_t index = 0;
    int32_t varIndex = 0;
    while (index != -1) {
        std::wstring varStr = _T("{") + std::to_wstring(varIndex) + _T("}");
        index = formattedString.Find(varStr.c_str(), 0);
        if (index != -1) {
            varIndex++;
        }
    }

    if (varIndex > 0) {
        UnicodeString result;
        Formattable* arguments = new Formattable[varIndex];
        if (arguments == nullptr) {
            return formattedString;
        }
        va_list list;
        va_start(list, originalString);
        int32_t count = va_arg(list, int32_t);
        varIndex = varIndex > count ? count : varIndex;

        for (int32_t i = 0; i < varIndex; ++i) {
            LPCTSTR vastr = va_arg(list, LPCTSTR);
            try {
                // 如挂在这里，请检查调用GetLocaleString时是否指定了参数的个数。
                arguments[i] = Formattable(vastr);
            } catch (...) {
                OutputDebugString(L"GetMultiVarStr format string with multiple strings error");
            }
        }
        va_end(list);

        UErrorCode err = U_ZERO_ERROR;
        MessageFormat::format(formattedString.GetData(), arguments, varIndex, result, err);

        delete[] arguments;
        arguments = nullptr;
        return (const wchar_t*)result.getTerminatedBuffer();
    } else {
        return formattedString;
    }
}

int32_t UICulture::UnicodeFormat(const string &pstrFormat, wstring &unicodeChar, va_list vaList)
{
    return UICultureImplement::UnicodeFormat(pstrFormat, unicodeChar, vaList);
}

std::wstring UICulture::GetPercentageStr(const int percentage)
{
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        auto text = cultureImplment->GetPercentageStr(percentage);
        return text;
    }
    return L"";
}

std::wstring UICulture::ToUpper(const wstring &src)
{
    std::lock_guard<mutex> guard(sequentialOper);
    for (const auto cultureImplment : cultureImplements) {
        if (cultureImplment == nullptr) {
            continue;
        }
        auto text = cultureImplment->ToUpper(src);
        return text;
    }
    return L"";
}

std::wstring UICulture::NumberLocalFormat(double value)
{
    std::lock_guard<mutex> guard(sequentialOper);
    const std::wstring errResult = L"";
    if (cultureImplements.empty()) {
        return errResult;
    }
    const auto cultureImplment = *cultureImplements.cbegin();
    if (cultureImplment == nullptr) {
        return errResult;
    }
    return cultureImplment->NumberLocalFormat(value);
}

} // namespace DuiLib